<?php

declare(strict_types=1);

namespace Core;

use Closure;
use Exception;

/**
 * routing with middleware
 */
class Router
{
    private Request $request;
    private array $middleware = [];
    private static array $cache = []; // Cache middleware and controller validation

    public function __construct(Request $request)
    {
        $this->request = $request;
        $this->middleware[] = \app\middleware\LogRequest::class;
    }

    public function middleware(string $middleware): self
    {
        $this->middleware[] = $middleware;
        return $this;
    }

    public function dispatch(): void
    {
        $uri      = trim(parse_url($this->request->getUri(), PHP_URL_PATH) ?? '/', '/');
        $segments = explode('/', $uri);
        array_shift($segments);

        $controllerName  = !empty($segments[0]) ? ucfirst($segments[0]) : 'Home';
        $action          = $segments[1] ?? 'index';
        $controllerClass = "app\\controller\\{$controllerName}Controller";
        $cacheKey        = "{$controllerClass}::{$action}";

        // Validate controller and action (cached)
        if (!isset(self::$cache[$cacheKey])) {
            $controllerFile = __DIR__ . "/../app/controller/{$controllerName}Controller.php";
            if (!file_exists($controllerFile) || !is_readable($controllerFile)) {
                http_response_code(404);
                throw new Exception("Controller not found: {$controllerName}");
            }
            if (!class_exists($controllerClass)) {
                http_response_code(500);
                throw new Exception("Class not found: {$controllerClass}");
            }
            self::$cache[$cacheKey] = true;
        }

        $controller = new $controllerClass($this->request);
        if (!is_callable([$controller, $action])) {
            http_response_code(404);
            throw new Exception("Action not found: {$action}");
        }

        // Build middleware pipeline
        $destination = fn() => call_user_func_array([$controller, $action], array_slice($segments, 2));
        $stack = $destination;
        foreach (array_reverse($this->middleware) as $middleware) {
            $cacheKey = "middleware:{$middleware}";
            if (!isset(self::$cache[$cacheKey])) {
                // if (!class_exists($middleware) || !(new $middleware() instanceof MiddlewareInterface)) {
                //     http_response_code(500);
                //     throw new Exception("Invalid middleware: {$middleware}");
                // }
                self::$cache[$cacheKey] = new $middleware();
            }
            $stack = fn(Request $req) => self::$cache[$cacheKey]->handle($req, $stack);
        }

        try {
            $stack($this->request);
        } catch (Exception $e) {
            http_response_code($e->getCode() ?: 500);
            echo json_encode(['error' => $e->getMessage()], JSON_THROW_ON_ERROR);
            exit;
        }
    }
}